/*
 * MIT License
 *
 * Copyright (c) 2019 Mr.css
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

package cn.seaboot.commons.core;

import cn.seaboot.commons.lang.Warning;

import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 日期类型只支持标准格式，其它格式，请转为字符串后，使用DateUtils进行转换
 *
 * @author Mr.css 2018年7月13日 上午11:13:34
 */
public class MapUtils {
    private MapUtils() {
    }


    /**
     * make a map
     *
     * @param objs array
     * @return map
     */
    public static Map<String, Object> newMap(Object... objs) {
        if (objs == null) {
            return Collections.emptyMap();
        }
        if (objs.length % 2 != 0) {
            throw new IllegalArgumentException("The length must be a multiple of 2!");
        }
        Map<String, Object> map = new HashMap<>(objs.length / 2);
        for (int i = 0; i < objs.length; i++) {
            map.put(objs[i++].toString(), objs[i]);
        }
        return map;
    }

    /**
     * 复制 map 中的字段
     *
     * @param src  源
     * @param tar  目标
     * @param keys 字段名
     */
    public static void cloneField(Map<String, Object> src, Map<String, Object> tar, String[] keys) {
        for (String k : keys) {
            src.put(k, tar.get(k));
        }
    }


    /**
     * 这个函数跟 map 的 getOrDefault() 很像，但是有着很本质的区别，
     * 当前函数 get() 之后，会将值放进 map 中
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    @SuppressWarnings({Warning.UNCHECKED, Warning.RAW_TYPES})
    public static <T> T getWithDefault(Map map, Object key, T def) {
        Object ret = map.get(key);
        if (ret == null) {
            map.put(key, def);
            return def;
        } else {
            return (T) Converter.convert(ret, def.getClass());
        }
    }

    /**
     * get value and convert to String
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    public static String getString(Map<?, ?> map, Object key, String def) {
        return Converter.toString(map.get(key), def);
    }

    /**
     * get value and convert to boolean
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    public static boolean getBool(Map<?, ?> map, Object key, boolean def) {
        return Converter.toBool(map.get(key), def);
    }

    /**
     * get value and convert to double
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    public static double getDouble(Map<?, ?> map, Object key, double def) {
        return Converter.toDouble(map.get(key), def);
    }

    /**
     * get value and convert to long
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    public static long getLong(Map<?, ?> map, Object key, long def) {
        return Converter.toLong(map.get(key), def);
    }

    /**
     * get value and convert to float
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    public static float getFloat(Map<?, ?> map, Object key, float def) {
        return Converter.toFloat(map.get(key), def);
    }

    /**
     * get value and convert to int
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    public static int getInteger(Map<?, ?> map, Object key, int def) {
        return Converter.toInteger(map.get(key), def);
    }

    /**
     * get value and convert to java.math.BigDecimal
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    public static java.math.BigDecimal getBigDecimal(Map<?, ?> map, Object key, java.math.BigDecimal def) {
        return Converter.toBigDecimal(map.get(key), def);
    }

    /**
     * get value and convert to Date
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    public static Date getDate(Map<?, ?> map, Object key, Date def) {
        return Converter.toDate(map.get(key), def);
    }

    /**
     * get value and convert to Time
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    public static Time getTime(Map<?, ?> map, Object key, Time def) {
        return Converter.toTime(map.get(key), def);
    }

    /**
     * get value and convert to Timestamp
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    public static Timestamp getTimestamp(Map<?, ?> map, Object key, Timestamp def) {
        return Converter.toTimestamp(map.get(key), def);
    }


    /**
     * get value and convert to LocalDate
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    public static LocalDate getLocalDate(Map<?, ?> map, Object key, LocalDate def) {
        return Converter.toLocalDate(map.get(key), def);
    }

    /**
     * get value and convert to LocalTime
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    public static LocalTime getLocalTime(Map<?, ?> map, Object key, LocalTime def) {
        return Converter.toLocalTime(map.get(key), def);
    }

    /**
     * get value and convert to LocalDateTime
     *
     * @param map map
     * @param key key
     * @param def default value
     * @return value
     */
    public static LocalDateTime getLocalDateTime(Map<?, ?> map, Object key, LocalDateTime def) {
        return Converter.toLocalDateTime(map.get(key), def);
    }

    /**
     * get value and convert to String
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static String getString(Map<?, ?> map, Object key) {
        return Converter.toString(map.get(key));
    }

    /**
     * get value and convert to Boolean
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Boolean getBool(Map<?, ?> map, Object key) {
        return Converter.toBool(map.get(key));
    }

    /**
     * get value and convert to Double
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Double getDouble(Map<?, ?> map, Object key) {
        return Converter.toDouble(map.get(key));
    }

    /**
     * get value and convert to Long
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Long getLong(Map<?, ?> map, Object key) {
        return Converter.toLong(map.get(key));
    }

    /**
     * get value and convert to Float
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Float getFloat(Map<?, ?> map, Object key) {
        return Converter.toFloat(map.get(key));
    }

    /**
     * get value and convert to Integer
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Integer getInteger(Map<?, ?> map, Object key) {
        return Converter.toInteger(map.get(key));
    }

    /**
     * get value and convert to java.math.BigDecimal
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static java.math.BigDecimal getBigDecimal(Map<?, ?> map, Object key) {
        return Converter.toBigDecimal(map.get(key));
    }

    /**
     * get value and convert to Date
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Date getDate(Map<?, ?> map, Object key) {
        return Converter.toDate(map.get(key));
    }

    /**
     * get value and convert to Time
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Time getTime(Map<?, ?> map, Object key) {
        return Converter.toTime(map.get(key));
    }

    /**
     * get value and convert to Timestamp
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Timestamp getTimestamp(Map<?, ?> map, Object key) {
        return Converter.toTimestamp(map.get(key));
    }

    /**
     * get value and convert to LocalDate
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static LocalDate getLocalDate(Map<?, ?> map, Object key) {
        return Converter.toLocalDate(map.get(key));
    }

    /**
     * get value and convert to LocalTime
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static LocalTime getLocalTime(Map<?, ?> map, Object key) {
        return Converter.toLocalTime(map.get(key));
    }

    /**
     * get value and convert to LocalDateTime
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static LocalDateTime getLocalDateTime(Map<?, ?> map, Object key) {
        return Converter.toLocalDateTime(map.get(key));
    }
}
